package com.auditlog.sql.dynamic;

import com.auditlog.datasource.ConnectionProxy;
import lombok.extern.slf4j.Slf4j;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class OracleSequenceCache {

    private static final Map<String, SequenceMeta> SEQUENCE_META_MAP = new ConcurrentHashMap<>();

    private static final String USER_SEQUENCE_SQL = "SELECT SEQUENCE_NAME,INCREMENT_BY,CACHE_SIZE FROM USER_SEQUENCES";

    private static final String NEXT_VAL = "NEXTVAL";

    private static final String CURR_VAL = "CURRVAL";

    private static final String SQL_CURR_SQL = "SELECT %s.CURRVAL FROM DUAL";

    private static final String ALL_SEQUENCE_SQL = "SELECT SEQUENCE_NAME,SEQUENCE_OWNER,INCREMENT_BY,CACHE_SIZE FROM ALL_SEQUENCES";


    public static SequenceMeta getSequenceMeta(String name, final ConnectionProxy connection) {
        if (SEQUENCE_META_MAP.size() == 0) {
            synchronized (OracleSequenceCache.class) {
                if (SEQUENCE_META_MAP.size() == 0) {
                    try {
                        Set<SequenceMeta> sequenceMetas = fetchAll(connection, USER_SEQUENCE_SQL, false);
                        sequenceMetas.addAll(fetchAll(connection, ALL_SEQUENCE_SQL, true));
                        sequenceMetas.forEach(sequenceMeta -> SEQUENCE_META_MAP.put(sequenceMeta.getName(), sequenceMeta));
                    } catch (Exception e) {
                        log.error("获取sequence异常", e);
                    }
                }
            }
        }
        return SEQUENCE_META_MAP.get(getKey(name));
    }


    public static String getKey(String name) {
        return name.toUpperCase(Locale.ROOT);
    }

    public static Set<SequenceMeta> fetchAll(ConnectionProxy connection, String sql, boolean isAll) throws SQLException {
        Set<SequenceMeta> sequenceMetas = new HashSet<>();
        try (PreparedStatement preparedStatement = connection.getTargetConnection().prepareStatement(sql)) {
            try (ResultSet resultSet = preparedStatement.executeQuery()) {
                while (resultSet.next()) {
                    String sequenceName = resultSet.getString("SEQUENCE_NAME");
                    String sequenceOwner = "";
                    if (isAll) {
                        sequenceOwner = resultSet.getString("SEQUENCE_OWNER");
                    } else {
                        sequenceOwner = connection.getDataSourceProxy().getUserName();
                    }
                    Long increment = resultSet.getLong("INCREMENT_BY");
                    Long cacheSize = resultSet.getLong("CACHE_SIZE");
                    SequenceMeta sequenceMeta = SequenceMeta.builder().cacheSize(cacheSize).owner(sequenceOwner).increment(increment).name(sequenceName).build();
                    sequenceMetas.add(sequenceMeta);
                }
            }
        }
        return sequenceMetas;
    }


    /**
     是否是序列值
     * @param name
     * @return: boolean
     */
    public static boolean isSequenceKey(String name) {
        return "NEXTVAL".equals(name.toUpperCase(Locale.ROOT));
    }


    /**
     * 获取序列的当前值
     *
     * @param seqName
     * @param connection
     * @return: java.lang.Long
     */
    public static Long getSeqCurVal(String seqName, ConnectionProxy connection) throws SQLException {
        String sql = String.format(SQL_CURR_SQL, seqName);
        Long currValue = null;
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
            try (ResultSet resultSet = preparedStatement.executeQuery()) {
                while (resultSet.next()) {
                    currValue = resultSet.getLong(1);
                }
            }
        }
        return currValue;
    }
}
